package config

import (
	"github.com/DiracLee/dires-go/logger"
	"github.com/spf13/viper"
	"os"
	"path/filepath"
	"time"
)

const (
	KeyAddress    = "server.address"
	KeyMaxConnect = "server.max_connect"
	KeyTimeout    = "server.timeout"
	KeyAppendOnly = "server.append_only"
	KeyAppendFile = "server.append_file"
	KeyPeers      = "server.peers"
	KeySelf       = "server.self"
	KeyDBIndex    = "server.db_index"
	KeyPassword   = "server.password"
)

var helper *viper.Viper

func init() {
	readConfig("conf")
	go heartbeat()
}

func heartbeat() {
	ticker := time.NewTicker(10 * time.Second)
	for {
		select {
		case <-ticker.C:
			readConfig("conf")
		}
	}
}

func readConfig(confDir string) {
	helper = viper.New()
	confDir = findConfDir(confDir)
	confPath := filepath.Join(confDir, "dires.yaml")
	helper.SetConfigFile(confPath)
	logger.Infof("[readConfig] SetConfigFile(%v)", confPath)
	if err := helper.ReadInConfig(); err != nil {
		logger.Error("[readConfig] helper failed to SetConfigFile")
	}
}

func GetAddress() string {
	return helper.GetString(KeyAddress)
}

func GetMaxConnect() int64 {
	return helper.GetInt64(KeyMaxConnect)
}

func GetTimeout() time.Duration {
	return getSeconds(KeyTimeout)
}

func GetAppendOnly() bool {
	return helper.GetBool(KeyAppendOnly)
}

func GetAppendFile() string {
	return helper.GetString(KeyAppendFile)
}

func GetPeers() []string {
	return helper.GetStringSlice(KeyPeers)
}

func GetPeersCount() int {
	return len(GetPeers())
}

func IsClusterNode() bool {
	return GetSelf() != "" && GetPeersCount() > 0
}

func GetSelf() string {
	return helper.GetString(KeySelf)
}

func GetDBIndex() int {
	return helper.GetInt(KeyDBIndex)
}

func GetPassWord() string {
	return helper.GetString(KeyPassword)
}

func getSeconds(seconds string) time.Duration {
	return time.Duration(helper.GetInt64(seconds)) * time.Second
}

func getMilliSeconds(seconds string) time.Duration {
	return time.Duration(helper.GetInt64(seconds)) * time.Second
}

const maxSearchDepth = 10

func findConfDir(confDir string, level ...int) string {
	depth := 0
	if len(level) > 0 {
		depth = level[0]
	}
	if depth > maxSearchDepth {
		return ""
	}
	if isDir(confDir) {
		return confDir
	}
	return findConfDir(filepath.Join("../", confDir), depth+1)
}

func isDir(path string) bool {
	info, err := os.Stat(path)
	return err == nil && info.IsDir()
}
